﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Xml.Linq;
using System.IO;
using Microsoft.SharePoint.Utilities;
using TST.DemoCode.Domain;
using System.Diagnostics;

namespace TST.DemoCode.FeatureReceivers
{
    public class RegisterThemes : SPFeatureReceiver
    {
        protected SPFeatureReceiverProperties _properties;

        public RegisterThemes()
        {
        }

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            Trace.WriteLine("TST.DemoCode.FeatureReceivers.RegisterTheme.FeatureInstalled");
            _properties = properties;
            try
            {
                Themes themes = ValidateProperties();
                if (themes != null)
                {
                    ModifySPTheme(themes, ModificationType.Add);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(String.Format("ERROR: {0}", ex.Message));
                throw;
            }
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            Trace.WriteLine("TST.DemoCode.FeatureReceivers.RegisterTheme.FeatureUninstalling");
            _properties = properties;
            try
            {

                Themes themes = ValidateProperties();
                if (themes != null)
                {
                    ModifySPTheme(themes, ModificationType.Remove);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(String.Format("ERROR: {0}", ex.Message));
                throw;
            }
        }

        private Themes ValidateProperties()
        {
            String fileName = GetSettingFromProperties("FileName", true);
            String fileDir = _properties.Definition.RootDirectory;
            if (!fileDir.EndsWith(@"\"))
            {
                fileDir += @"\";
            }
            fileName = fileDir + fileName;
            Trace.WriteLine(String.Format("File name xml file: {0}.", fileName));
            if (!File.Exists(fileName))
            {
                throw new SPException(String.Format("File not found: {0}.", fileName));
            }
            Trace.WriteLine(String.Format("Load XML: {0}.", fileName));
            XDocument xmlFile = XDocument.Load(fileName);
            XNamespace nmsp = XNamespace.Get(Theme.XmlNameSpaceThemes);
            var query = from c in xmlFile.Elements(nmsp + "Themes") select c;
            Themes themes = new Themes();
            if (themes.GetFromXml(query.FirstOrDefault()))
            {
                Trace.WriteLine(String.Format("Themes found: {0}.", themes.ThemeList.Count));
                return themes;
            }
            return null;
        }

        private void ModifySPTheme(Themes themes, ModificationType type)
        {
            XDocument doc = null;
            XNamespace ns = "http://tempuri.org/SPThemes.xsd";

            foreach (Theme theme in themes.ThemeList)
            {
                // path to the SPTHEMES.XML file
                string spthemePath = Path.Combine(SPUtility.GetGenericSetupPath(String.Format(@"TEMPLATE\LAYOUTS\{0}", theme.LCID)), "SPTHEMES.XML");
                Trace.WriteLine(String.Format("Themes xml file: {0}.", spthemePath));

                if (!File.Exists(spthemePath))
                {
                    continue;
                }

                // read the contents of the SPTHEMES.XML file
                Trace.WriteLine("Read Themes XML");
                string contents = string.Empty;
                using (StreamReader streamReader = new StreamReader(spthemePath))
                {
                    contents = streamReader.ReadToEnd();
                    streamReader.Close();
                }

                using (StringReader stringReader = new StringReader(contents.Trim()))
                {
                    // create a new XDocument from the contents of the file
                    doc = XDocument.Load(stringReader);

                    // retrieve all elements with the TemplateID.  At most, there should only be one
                    var element = from b in doc.Element(ns + "SPThemes").Elements(ns + "Templates")
                                  where b.Element(ns + "TemplateID").Value == theme.TemplateID
                                  select b;

                    // determine if the theme element already exists
                    bool exists = (element != null && element.Count() > 0);

                    if (type == ModificationType.Add)
                    {
                        Trace.WriteLine(String.Format("Check if theme by ID exists: {0} (LCID={1}).", theme.TemplateID, theme.LCID));
                        if (!exists && theme.Validate())
                        {
                            Trace.WriteLine(String.Format("Theme {0} does not exist. Add", theme.TemplateID));
                            // create an XElement that defines our custom theme
                            XElement xml =
                                new XElement(ns + "Templates",
                                    new XElement(ns + "TemplateID", theme.TemplateID),
                                    new XElement(ns + "DisplayName", theme.DisplayName),
                                    new XElement(ns + "Description", theme.Description),
                                    new XElement(ns + "Thumbnail", theme.Thumbnail),
                                    new XElement(ns + "Preview", theme.Preview));

                            // add the element to the file and save
                            doc.Element(ns + "SPThemes").Add(xml);
                            Trace.WriteLine("Save Themes XML");
                            doc.Save(spthemePath);
                        }
                    }
                    else
                    {
                        if (exists)
                        {
                            // if the element exists, remove it and save
                            Trace.WriteLine(String.Format("Remove theme {0}.", theme.TemplateID));
                            element.Remove();
                            doc.Save(spthemePath);
                        }
                    }

                    stringReader.Close();
                }
            }
        }

        protected String GetSettingFromProperties(string propertyName, bool required)
        {
            if (_properties == null)
            {
                throw new SPException("Properties not found.");
            }
            SPFeatureProperty property = null;
            foreach (SPFeatureProperty search in _properties.Definition.Properties)
                if (String.Compare(search.Name, propertyName, true) == 0)
                    property = search;
            if (property == null)
                throw new SPException(string.Format("Property {0} not found in the Feature Definition", propertyName));
            if (required && string.IsNullOrEmpty(property.Value.Trim()))
                throw new SPException(string.Format("Property {0} must have a value in the Feature Definition", propertyName));
            return property.Value;
        }
    }

    internal enum ModificationType
    {
        Add,
        Remove
    }
}
